package TrainModel;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

import Utilities.logFileIO;
import Utilities.TrainConstants;

// Holds the unit tests for the Train Model class and sub classes
public class TrainCarUnitTests
{
	// log file writer for the unit tests
	private logFileIO utLogFile;
	
	public TrainCarUnitTests()
	{
		// Init log file writer
		utLogFile = new logFileIO( "TrainCar_UnitTest_LogFile", "txt" );
	}
	
	@Test
	// Testing that new train has no conductor
	public void newCondCar()
	{
		TrainCar testCC = new TrainCar(utLogFile, 0);
		assertFalse(testCC.getConductor());
	}
	
	@Test
	// Testing that conductor can be loaded
	public void newCondCarLoad()
	{
		TrainCar testCC = new TrainCar(utLogFile, 0);
		testCC.loadConductor();
		assertTrue(testCC.getConductor());
	}
	
	@Test
	// Testing that new passenger car has no passengers
	public void newPassengerCar()
	{
		TrainCar testTC = new TrainCar(utLogFile, 0);
		assertTrue(testTC.getNumPassengers() == 0);
	}
	
	@Test
	// Testing that new passenger car can load passengers
	public void newPassengerCarLoad()
	{
		TrainCar testPC = new TrainCar(utLogFile, 0);
		testPC.openDoors();
		testPC.setPassengerFlow(10);
		assertTrue(testPC.getNumPassengers() == 10);
	}
	
	@Test
	// Testing that new passenger car cannot have negative passengers
	public void newPassengerCarCannotHaveNeg()
	{
		TrainCar testPC = new TrainCar(utLogFile, 0);
		testPC.setPassengerFlow(10);
		testPC.setPassengerFlow(-20);
		assertTrue(testPC.getNumPassengers() == 0);
	}

	@Test
	// Testing that new passenger car has base weight
	public void newPassengerCarHasBaseWeight()
	{
		TrainCar testCC = new TrainCar(utLogFile, 0);
		double weight = testCC.getWeight();
		assertTrue(weight == TrainConstants.CAR_BASE_WEIGHT);
	}
	
	@Test
	// Testing that new passenger car weight remains the same after loading and completely unloading
	public void newPassengerCarLoadAndUnloadWeight()
	{
		TrainCar testCC = new TrainCar(utLogFile, 0);
		double weightBefore = testCC.getWeight();
		testCC.setPassengerFlow(30);
		testCC.setPassengerFlow(-30);
		double weightAfter = testCC.getWeight();
		assertTrue(weightBefore == weightAfter);
	}
	
	@Test
	// Testing that new passenger car weight increases correctly after loading
	public void newPassengerCarLoadWeight()
	{
		TrainCar testPC = new TrainCar(utLogFile, 0);
		testPC.openDoors();
		testPC.setPassengerFlow(30);
		double weight1 = testPC.getWeight();
		double weight2 = TrainConstants.CAR_BASE_WEIGHT + (TrainConstants.PASSENGER_WEIGHT*30);
		assertTrue(weight1 == weight2);
	}
	
	
	@Test
	// Testing that passenger car weight is base weight after trying to load too many passengers
	public void newPassengerCarLoadTooManyWeight()
	{
		TrainCar testPC = new TrainCar(utLogFile, 0);
		testPC.openDoors();
		testPC.setPassengerFlow(300);
		double weight1 = testPC.getWeight();
		double weight2 = TrainConstants.CAR_BASE_WEIGHT + (TrainConstants.PASSENGER_WEIGHT*222);
		assertTrue(weight1 == weight2);
	}
	
	 @Test
	// Testing that passenger car weight is correct after unloading valid number of passengers
	public void newPassengerCarUnLoadWeight()
	{
		 TrainCar testPC = new TrainCar(utLogFile, 0);
		testPC.openDoors();
		testPC.setPassengerFlow(30);
		testPC.setPassengerFlow(-15);
		double weight1 = testPC.getWeight();
		double weight2 = TrainConstants.CAR_BASE_WEIGHT + (TrainConstants.PASSENGER_WEIGHT*15);
		assertTrue(weight1 == weight2);
	}
	
	@Test
	// Testing that the loading the conductor increments the weight
	public void newConductorCarLoadConductorWeight()
	{
		TrainCar testCC = new TrainCar(utLogFile, 0);
		testCC.loadConductor();
		double weight1 = testCC.getWeight();
		double weight2 = TrainConstants.CAR_BASE_WEIGHT + TrainConstants.PASSENGER_WEIGHT;
		assertTrue(weight1 == weight2);
	}
	 
	@Test
	// Testing that loading and unloading the conductor returns the weight to original value
	public void newConductorCarLoadAndUnloadConductorWeight()
	{
		TrainCar testCC = new TrainCar(utLogFile, 0);
		testCC.loadConductor();
		testCC.removeConductor();
		double weight1 = testCC.getWeight();
		double weight2 = TrainConstants.CAR_BASE_WEIGHT;
		assertTrue(weight1 == weight2);
	}
	 
	@Test
	// Testing load and unload of conductor at the same time as load and unload of passengers
	public void newConductorCarComplexLoadUnload()
	{
		TrainCar testCC = new TrainCar(utLogFile, 0);
		testCC.openDoors();
		testCC.loadConductor();
		testCC.setPassengerFlow(300);
		testCC.removeConductor();
		testCC.setPassengerFlow(-200);
		testCC.loadConductor();
		double weight1 = testCC.getWeight();
		double weight2 = TrainConstants.CAR_BASE_WEIGHT + TrainConstants.PASSENGER_WEIGHT + (22*TrainConstants.PASSENGER_WEIGHT);
		assertTrue(weight1 == weight2);
	}

	@Test
	// Testing Lights start off
	public void lightsStartOff()
	{
		TrainCar testTC = new TrainCar(utLogFile, 0);
		boolean testRet = testTC.areLightsOn();
		assertFalse(testRet);
	}
	
	@Test
	// Testing lights can be turned on
	public void lightsTurnOn()
	{
		TrainCar testTC = new TrainCar(utLogFile, 0);
		testTC.turnLightsOn();
		boolean testRet = testTC.areLightsOn();
		assertTrue(testRet);
	}
	
	@Test
	// Testing lights can be turned off
	public void lightsTurnOff()
	{
		TrainCar testTC = new TrainCar(utLogFile, 0);
		testTC.turnLightsOn();
		testTC.turnLightsOff();
		boolean testRet = testTC.areLightsOn();
		assertFalse(testRet);
	}
	
	@Test
	// Testing Doors start closed
	public void doorsStartClosed()
	{
		TrainCar testTC = new TrainCar(utLogFile, 0);
		boolean testRet = testTC.areDoorsOpen();
		assertFalse(testRet);
	}
	
	@Test
	// Testing doors can be opened
	public void doorsCanOpen()
	{
		TrainCar testTC = new TrainCar(utLogFile, 0);
		testTC.openDoors();
		boolean testRet = testTC.areDoorsOpen();
		assertTrue(testRet);
	}
	
	@Test
	// Testing doors can be closed
	public void doorsCanClose()
	{
		TrainCar testTC = new TrainCar(utLogFile, 0);
		testTC.openDoors();
		testTC.closeDoors();
		boolean testRet = testTC.areDoorsOpen();
		assertFalse(testRet);
	}
	
	@Test
	// Testing passengers cannot be loaded with closed doors
	public void doorsMustBeOpenForPassengers()
	{
		TrainCar testPC = new TrainCar(utLogFile, 0);
		testPC.openDoors();
		testPC.closeDoors();
		int ret = testPC.setPassengerFlow(15);
		assertTrue(ret == -1);
	}
}
